package com.xiaozhu.utils.algorithm;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class RouteSelector {

    // 用于避免除零错误的一个极小值常量
    private static final double EPS = 1e-6;

    /**
     * 安全地从 JSONObject 中读取一个 double 值
     * 支持传入多个可能的字段名，找到第一个存在的就返回对应的值
     *
     * @param r    JSONObject 数据
     * @param keys 可能的字段名列表（如 "distance", "distance_value", "distance_meter"）
     * @return double 值，如果都不存在则返回 0
     */
    private static double getDoubleSafe(JSONObject r, String... keys) {
        for (String k : keys) {
            if (r.containsKey(k)) { // 如果包含这个字段
                return r.getDoubleValue(k); // 直接返回其 double 值
            }
        }
        return 0d; // 没找到任何字段，默认返回 0
    }

    /**
     * 使用加权评分算法，从多条路线中选出最优路线
     *
     * @param routes    路线列表，JSONArray，每个元素是一个 JSONObject，通常包含 distance、duration、tolls 等字段
     * @param wDistance 距离权重，取值范围 0-1，越大越重视距离
     * @param wDuration 耗时权重，取值范围 0-1，越大越重视耗时
     * @param wToll     通行费权重，取值范围 0-1，越大越重视费用
     * @return 最优路线的 JSONObject（会额外带一个 "_score" 字段表示加权分数）
     */
    public static JSONObject selectBestByWeightedScore(JSONArray routes,
                                                       double wDistance,
                                                       double wDuration,
                                                       double wToll) {
        // 如果没有路线数据，直接返回 null
        if (routes == null || routes.isEmpty()) return null;

        int n = routes.size();

        // 用于存储每条路线的距离、耗时、费用
        List<Double> distances = new ArrayList<>(n);
        List<Double> durations = new ArrayList<>(n);
        List<Double> tolls = new ArrayList<>(n);

        // 遍历所有路线，提取原始数据
        for (int i = 0; i < n; i++) {
            JSONObject r = routes.getJSONObject(i);
            // 百度返回的单位一般是：distance(米)、duration(秒)
            double dist = getDoubleSafe(r, "distance", "distance_value", "distance_meter");
            double dur = getDoubleSafe(r, "duration", "duration_value", "duration_second");
            double toll = getDoubleSafe(r, "tolls", "toll", "fee", "price"); // 尝试读取通行费字段

            distances.add(dist);
            durations.add(dur);
            tolls.add(toll);
        }

        // 计算每个维度的最小值和最大值，用于归一化
        double minD = distances.stream().min(Double::compareTo).orElse(0d);
        double maxD = distances.stream().max(Double::compareTo).orElse(0d);
        double minT = durations.stream().min(Double::compareTo).orElse(0d);
        double maxT = durations.stream().max(Double::compareTo).orElse(0d);
        double minFee = tolls.stream().min(Double::compareTo).orElse(0d);
        double maxFee = tolls.stream().max(Double::compareTo).orElse(0d);

        JSONObject best = null;              // 最优路线
        double bestScore = Double.POSITIVE_INFINITY; // 当前最优分数，越小越好

        // 遍历每条路线，计算其加权分数
        for (int i = 0; i < n; i++) {
            double d = distances.get(i);
            double dur = durations.get(i);
            double fee = tolls.get(i);

            // 归一化：将每个值映射到 0-1 区间，便于加权比较
            double normD = (maxD - minD) > EPS ? (d - minD) / (maxD - minD) : 0.5;
            double normDur = (maxT - minT) > EPS ? (dur - minT) / (maxT - minT) : 0.5;
            double normFee = (maxFee - minFee) > EPS ? (fee - minFee) / (maxFee - minFee) : 0.5;

            // 加权求和：分数越小越优
            double score = wDistance * normD + wDuration * normDur + wToll * normFee;

            // 比较当前路线是否优于已有最优路线
            // 如果分数更低，或者分数相同但距离更短，则更新最优路线
            if (score < bestScore ||
                    (Math.abs(score - bestScore) < 1e-9 && d < getDoubleSafe(best, "distance", "distance_value"))) {
                bestScore = score;
                best = routes.getJSONObject(i);
                best.put("_score", score); // 将计算出的分数放入返回对象，便于调试或展示
            }
        }

        return best;
    }
}
